using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using WPCoco.Tasks;
using WPCoco.Controllers;
using Microsoft.Xna.Framework.Input.Touch;
using System.Diagnostics;

namespace WPCoco.Specialized
{
    public class PagedScene : Scene
    {
        public PagedScene()
        {
            this.IsRunningChange += new EventHandler(PagedScene_IsRunningChange);
        }

        void PagedScene_IsRunningChange(object sender, EventArgs e)
        {
            if (IsRunning)
                ConnectToTouchScreen();
            else
                DisconnectFromTouchScreen();
        }

        void ConnectToTouchScreen() 
        {
            ControllerManager.Shared.TouchScreen.StartDrag += new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_StartDrag);
            ControllerManager.Shared.TouchScreen.Dragging += new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_Dragging);
            ControllerManager.Shared.TouchScreen.EndDrag += new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_EndDrag);
        }

        void DisconnectFromTouchScreen()
        {
            ControllerManager.Shared.TouchScreen.StartDrag -= new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_StartDrag);
            ControllerManager.Shared.TouchScreen.Dragging -= new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_Dragging);
            ControllerManager.Shared.TouchScreen.EndDrag -= new EventHandler<CustomEventArgs<GestureSample>>(TouchScreen_EndDrag);
        }

        Vector2 downPoint;
        float startOffset;

        void TouchScreen_StartDrag(object sender, CustomEventArgs<GestureSample> e)
        {
            StopAnimation();
            startOffset = offset;
            downPoint = e.Value.Position;
        }

        void TouchScreen_Dragging(object sender, CustomEventArgs<GestureSample> e)
        {
            Vector2 delta = e.Value.Position - downPoint;

            Matrix m = MatrixHelper.GetViewWorldMatrix(this);
            delta = Vector2.TransformNormal(delta, m);

            Offset = startOffset - delta.X;
        }

        void TouchScreen_EndDrag(object sender, CustomEventArgs<GestureSample> e)
        {
            float delta = offset - startOffset;
            bool swap = Math.Abs(delta) > Screen.Width / 6;
             
            int page = (int)Math.Round(startOffset / (float)Screen.Width);
            int pagea = (int)(offset / Screen.Width);
            int pageb = (int)((offset + Screen.Width) / Screen.Width);

            int nearPage = 0;
            if (swap)
                if (page == pagea) nearPage = pageb; else nearPage = pagea; 
            else 
                if (page == pagea) nearPage = pagea; else nearPage = pageb;
            if (nearPage < 0) nearPage = 0;
            if (nearPage >= pages.Count) nearPage = pages.Count - 1;
            GotoPageAnimated(nearPage);
        }

        List<Scene> pages = new List<Scene>();

        float offset = 0;

        public float Offset
        {
            get { return offset; }
            set 
            { 
                offset = value;
                ArrangePages();
            }
        }

        public int Count { get { return pages.Count; } }

        int activeIndex;

        public int ActiveIndex
        {
            get { return activeIndex; }
            private set 
            {
                if (activeIndex == value) return;
                activeIndex = value;
                RaiseActivePageChange(pages[activeIndex]);
            }
        }

        void ArrangePages() 
        {
            Scene scene;
            for (int i = 0; i < pages.Count; i++)
            {
                scene = pages[i];
                scene.Position = new Vector2(i * Screen.Width - offset, 0);
                scene.Anchor = Vector2.Zero;
            }
        }

        Task animation;

        public void AddPage(Scene node) 
        {
            pages.Add(node);
            AddNode(node, int.MinValue);
            ArrangePages();
        }

        void StopAnimation() 
        {
            if (animation != null) animation.Stop();
        }

        public void GotoPageAnimated(int index)
        {
            StopAnimation();
            float delta = (float)Math.Abs(offset - index * Screen.Width);
            float duration = (float)Math.Sqrt(delta / (float)Screen.Width * 1.5f);
            animation = new Spawn(
                            new EaseExponentialOut(new FloatAnimation("Offset", offset, index * Screen.Width, duration)),
                            new Sequence(
                                new FiniteTime(duration / 4),
                                new DelegateTask(new Action(() => 
                                {
                                    ActiveIndex = index;
                                }))));

            RunTask(animation);

        }

        public void GotoPage(int index) 
        {
            Offset = index * Width;
            ActiveIndex = index;
        }

        public event EventHandler<CustomEventArgs<Scene>> ActivePageChange;

        void RaiseActivePageChange(Scene page) 
        {
            if (ActivePageChange == null) return;
            ActivePageChange(this, new CustomEventArgs<Scene>(page));
        }
    }
}
